package com.google.code.jmarias.client.tcp;

import com.google.code.jmarias.common.ActionSerializer;
import com.google.code.jmarias.common.action.AbstractAction;
import com.google.code.jmarias.common.action.AbstractSignedMessage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Vlakno pro pripojeni pres TCP socket, zajistuje jeho komunikaci se serverem.
 * @author Ondrej Michal
 */
public class SocketClientInterface extends Thread {

    private ActionSerializer serializer = ActionSerializer.newInstance();
    private RemoteServer server;
    private Queue<AbstractSignedMessage> serverToClientActions = new ConcurrentLinkedQueue<AbstractSignedMessage>();
    private Queue<AbstractAction> clientToServerActions = new ConcurrentLinkedQueue<AbstractAction>();

    @Override
    public void run() {
        Socket socket = null;
        try {
            socket = new Socket("localhost", 4444);
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            createServer();

            while (true) {
                try { // Poll every ~1000 ms
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }

                if (in.ready()) {
                    String xml = in.readLine();
//                    System.out.println("server2client: " + xml);
                    serverToClientActions.offer(serializer.deserializeSignedMessage(xml));
                }

                AbstractAction action = clientToServerActions.poll();
                if (action != null) {
//                    System.out.println("posilam " + action);
                    serializer.serialize(action, out);
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close(); // closes also in and out, see javadoc
                } catch (IOException ex) {
                }
            }
        }
    }

    public Queue<AbstractSignedMessage> getIncomingActions() {
        return serverToClientActions;
    }

    private synchronized void createServer() {
        server = new RemoteServer(clientToServerActions);
        notifyAll();
    }

    /**
     * Vraci instanci tridy RemoteServer vytvorenou timto vlaknem. Nesmi se
     * volat, pokud vlakno neni spustene.
     * @TODO co se stane, kdyz selze vytvareni RemoteServeru?
     */
    public synchronized RemoteServer getServer() {
        while (server == null) {
            try {
                wait();
            } catch (InterruptedException ex) {}
        }
        return server;
    }

    public static void main(String[] args) throws IOException {
        new SocketClientInterface().start();
    }
}